#include "vsf.h"

#include "btstack_linked_list.h"
#include "btstack_debug.h"

#include "btstack_run_loop_vsf.h"

struct btstack_vsf_t
{
	btstack_linked_list_t timers;
	struct vsftimer_t vsftimer;
	struct vsfsm_t sm;
} static btstack_vsf;

static uint32_t btstack_run_loop_vsf_get_time_ms(void)
{
	return vsfhal_tickclk_get_ms();
}

static void btstack_run_loop_vsf_set_timer(btstack_timer_source_t *ts, uint32_t timeout_in_ms)
{
	ts->timeout = btstack_run_loop_vsf_get_time_ms() + timeout_in_ms + 1;
}

static void btstack_run_loop_vsf_add_timer(btstack_timer_source_t *ts)
{
	btstack_linked_item_t *it;
	for (it = (btstack_linked_item_t *)&btstack_vsf.timers; it->next; it = it->next)
	{
		if ((btstack_timer_source_t *)it->next == ts)
		{
			log_error("btstack_run_loop_timer_add error: timer to add already in list!");
			return;
		}
		if (ts->timeout < ((btstack_timer_source_t *)it->next)->timeout)
			break;
	}
	ts->item.next = it->next;
	it->next = (btstack_linked_item_t *)ts;
}

static int btstack_run_loop_vsf_remove_timer(btstack_timer_source_t *ts)
{
	return btstack_linked_list_remove(&btstack_vsf.timers, (btstack_linked_item_t *)ts);
}

static void btstack_run_loop_vsf_dump_timer(void)
{
	btstack_linked_item_t *it;
	int i = 0;
	for (it = (btstack_linked_item_t *)btstack_vsf.timers; it; it = it->next)
	{
		btstack_timer_source_t *ts = (btstack_timer_source_t *)it;
		log_info("timer %u, timeout %u\n", i, (unsigned int)ts->timeout);
	}
}

static void btstack_run_loop_vsf_on_timer(void *param)
{
	uint32_t now = btstack_run_loop_vsf_get_time_ms();
	while (btstack_vsf.timers)
	{
		btstack_timer_source_t *ts = (btstack_timer_source_t *)btstack_vsf.timers;
		if (ts->timeout > now)
			break;
		btstack_run_loop_vsf_remove_timer(ts);
		ts->process(ts);
	}
}

static void btstack_run_loop_vsf_init(void)
{
	memset(&btstack_vsf, 0, sizeof(btstack_vsf));
	vsfsm_notifier_set_cb(&btstack_vsf.vsftimer.notifier, btstack_run_loop_vsf_on_timer, NULL);
	btstack_vsf.vsftimer.trigger_cnt = -1;
	btstack_vsf.vsftimer.interval = 1;
	vsftimer_enqueue(&btstack_vsf.vsftimer);
}

static const btstack_run_loop_t btstack_run_loop_vsf =
{
	.init = btstack_run_loop_vsf_init,
	.add_data_source = NULL,
	.remove_data_source = NULL,
	.enable_data_source_callbacks = NULL,
	.disable_data_source_callbacks = NULL,
	.set_timer = btstack_run_loop_vsf_set_timer,
	.add_timer = btstack_run_loop_vsf_add_timer,
	.remove_timer = btstack_run_loop_vsf_remove_timer,
	.execute = NULL,
	.dump_timer = btstack_run_loop_vsf_dump_timer,
	.get_time_ms = btstack_run_loop_vsf_get_time_ms,
};

const btstack_run_loop_t * btstack_run_loop_vsf_get_instance(void)
{
	return &btstack_run_loop_vsf;
}

